/**
 * - `1 s e newValue`：数组片段$A[s...e]$的每一个元素均变为$newValue$，$newValue$必然属于$\{0,1\}$；
 * - `2 s e`：数组片段$A[s...e]$的每一个元素均与`1`进行异或，即`01`翻转；
 * - `3 s e`：求数组片段$A[s...e]$之和，并输出；
 * - `4 s e`：求数组片段$A[s...e]$最长的连续`1`的数量，并输出；
 * - `5 s e`：求数组片段$A[s...e]$中`0`的数量，并输出；
 * - `6 s e`：求数组片段$A[s...e]$中最长的连续`0`的数量，并输出；
 * - `7 s e`：求数组片段$A[s...e]$中的段数，所谓段数请参考样例
 * - `8 s e`：将数组片段$A[s...e]$转置，即首尾元素交换、正数其次元素和倒数其次元素交换、……；
 * - `9 s e k`：将数组片段$A[s...e]$循环右移位$k$位，注意$k$为负数则循环左移；
 * - `10 s e pos`：将数组片段$A[s...e]$在数组中移动位置，移动之后，原$A[s]$要位于$pos$位置，其后依次往后直到$A[e]$，显然，移动之后原$A[pos]$元素将位于$pos+e-s+1$位置；
 * - `11 s e`：删除数组片段$A[s...e]$，其后的元素依次前移；
 * - `12 pos newValue`：将$value$插入到数组的$pos$位置，原$A[pos]$及其之后的元素依次后移。
 * 
 */
#include <bits/stdc++.h>
using namespace std;

#include <bits/extc++.h>
using namespace __gnu_pbds;

template <typename T>
const T & mymax(const T & a, const T & b){
    return max(a, b);
}

template<typename T, typename ... Args>
const T & mymax(const T & t, const Args & ... args){
    return max(t, mymax(args ...));
}

struct SplayTree{ // 伸展树维护区间数据, 有效区间[1...n], 操作前要init && build

using llt = long long;

struct value_type{
    array<int, 2> cnt; // 0和1的数量
    array<int, 2> longest; // 0和1的最长连续长度
    array<pair<int, int>, 2> bound; // 0和1的左右边界的长度
    int duanshu; // 段数 

    value_type():cnt{0, 0}{};
    value_type(int t){
        if(1 == t){
            cnt = {0, 1};
            longest = {0, 1};
            bound = {pair<int, int>{0, 0}, pair<int, int>{1, 1}};            
        }else{
            cnt = {1, 0};
            longest = {1, 0};
            bound = {pair<int, int>{1, 1}, pair<int, int>{0, 0}};
        }
        duanshu = 1;
    }

};

using data_type = int;  // 本身的数据类型
// using value_type = int; // 维护信息的类型
using lazy_type = int;  // 延迟标记类型, 第0位为1表示要异或，第1位为1表示要置1，第2位为1表示要清零

static int const LEFT = 0;
static int const RIGHT = 1;

struct node_t { // 节点的类型 
    int parent;
    int son[2];
	int size;   // size域, 子树的节点数量
	data_type data;   // 本身的数据
	int flip;         // 翻转标记，也是延迟标记的一种
	value_type value; // 维护信息
	lazy_type lazy;   // 延迟标记
};

int Root;
vector<node_t> Nodes; // 0表示NULL且Nodes[0]中保证全是0
int toUsed;

// 从下往上计算value，用于pushUp，伸展树应保证ls与rs均有意义
value_type _up_(const value_type & ls, const value_type & rs) {
	// assert(0);

    value_type ans;
    if(ls.duanshu == 1){
        if(rs.duanshu == 1){
            int lt = 0;
            if(ls.cnt[lt] == 0) lt = 1;
            int rt = 0;
            if(rs.cnt[rt] == 0) rt = 1;

            if(lt == rt){
                ans.cnt[lt] = ans.longest[lt] = ans.bound[lt].first = ans.bound[lt].second = ls.cnt[lt] + rs.cnt[lt];
                ans.cnt[lt ^ 1] = ans.longest[lt ^ 1] = ans.bound[lt ^ 1].first = ans.bound[lt ^ 1].second = 0;
                ans.duanshu = 1;
            }else{
                ans.cnt[lt] = ans.longest[lt] = ans.bound[lt].first = ls.cnt[lt];
                ans.cnt[rt] = ans.longest[rt] = ans.bound[rt].second = rs.cnt[rt];
                ans.bound[lt].second = ans.bound[rt].first = 0;
                ans.duanshu = 2;
            }
        }else{
            int t = 0;
            if(ls.cnt[t] == 0) t = 1;

            ans.cnt = {ls.cnt[0] + rs.cnt[0], ls.cnt[1] + rs.cnt[1]};
            ans.longest[t ^ 1] = rs.longest[t ^ 1];
            ans.longest[t] = max(ls.cnt[t] + rs.bound[t].first, rs.longest[t]);
            ans.bound[t].first = ls.cnt[t] + rs.bound[t].first;
            ans.bound[t].second = rs.bound[t].second;
            ans.bound[t ^ 1].first = 0;
            ans.bound[t ^ 1].second = rs.bound[t ^ 1].second;
            ans.duanshu = rs.duanshu;
            if(rs.bound[t].first == 0) ans.duanshu += 1;
        }
    }else{
        if(rs.duanshu == 1){
            int t = 0;
            if(rs.cnt[t] == 0) t = 1;

            ans.cnt = {ls.cnt[0] + rs.cnt[0], ls.cnt[1] + rs.cnt[1]};
            ans.longest[t ^ 1] = ls.longest[t ^ 1];
            ans.longest[t] = max(ls.bound[t].second + rs.cnt[t], ls.longest[t]);
            ans.bound[t].first = ls.bound[t].first;
            ans.bound[t].second = ls.bound[t].second + rs.cnt[t];
            ans.bound[t ^ 1] = {ls.bound[t ^ 1].first, 0};
            ans.duanshu = ls.duanshu;
            if(ls.bound[t].second == 0) ans.duanshu += 1;
        }else{
            ans.cnt = {ls.cnt[0] + rs.cnt[0], ls.cnt[1] + rs.cnt[1]};
            ans.bound = {pair<int, int>{ls.bound[0].first, rs.bound[0].second}, pair<int, int>{ls.bound[1].first, rs.bound[1].second}};
            ans.longest = {
                mymax(ls.longest[0], rs.longest[0], ls.bound[0].second + rs.bound[0].first),
                mymax(ls.longest[1], rs.longest[1], ls.bound[1].second + rs.bound[1].first) 
            };

            ans.duanshu = ls.duanshu + rs.duanshu;
            if((ls.bound[0].second == 0 and rs.bound[0].first == 0) or (ls.bound[1].second == 0 and rs.bound[1].first == 0)) ans.duanshu -= 1;
        }
    }

    return ans;
}

// 根据变动信息delta计算本节点的信息并且打延迟标记，用于pushDown或者modify
void _dn_(int t, const lazy_type & delta, int flip) {
    auto & n = Nodes[t];
    auto & v = n.value;

	/// 首先处理翻转
    if(flip){
		swap(n.son[LEFT], n.son[RIGHT]);
		swap(v.bound[0].first, v.bound[0].second);
		swap(v.bound[1].first, v.bound[1].second);
	}

    if(delta & 0x2){ // 置1
        n.data = 1;
        v.cnt = v.longest = {0, n.size};
        v.bound = {pair<int, int>{0, 0}, pair<int, int>{n.size, n.size}};
        v.duanshu = 1;
    }else if(delta & 0x4){ // 置零
        n.data = 0;
        v.cnt = v.longest = {n.size, 0};
        v.bound = {pair<int, int>{n.size, n.size}, pair<int, int>{0, 0}};
        v.duanshu = 1;        
    }

    if(delta & 1){ // yihuo
        n.data ^= 1;
        swap(v.cnt[0], v.cnt[1]);
        swap(v.longest[0], v.longest[1]);
        swap(v.bound[0].first, v.bound[1].first);
        swap(v.bound[0].second, v.bound[1].second);
    }

    if(delta & 0x6) n.lazy = delta;
	else n.lazy ^= (delta & 1);

	n.flip ^= flip;
    return;
}

/// 根据给定的data生成维护的信息
static value_type mkValue(const data_type & data) {
	// assert(0);
    if(data){
        return value_type(1);
    }
    return value_type(0);
}

static const value_type value_zero() {
	static const value_type VALUE_0;
	return VALUE_0;
}

static const lazy_type lazy_zero() {
	static const lazy_type LAZY_0 = 0;
	return LAZY_0;
}

static const data_type data_zero() {
	static const data_type DATA_0 = 0;
	return DATA_0;
}

// 返回节点t的排行, 保证不对树根调用
int _sn(int t) {
	assert(t != Root);
	return Nodes[Nodes[t].parent].son[LEFT] == t ? LEFT : RIGHT;
}

// 根据t节点的儿子，计算t节点
void _pushUp(int t) {
	Nodes[t].size = 1;
	Nodes[t].value = mkValue(Nodes[t].data);
    int son = Nodes[t].son[LEFT];
	if(son) {
		Nodes[t].size += Nodes[son].size;
		Nodes[t].value = _up_(Nodes[son].value, Nodes[t].value);
	}
	son = Nodes[t].son[RIGHT];
	if(son) {
		Nodes[t].size += Nodes[son].size;
		/// 必须t在左、右儿子在右
		Nodes[t].value = _up_(Nodes[t].value, Nodes[son].value);
	}
	return;
}

// 根据t的延迟去计算t的儿子
void _pushDown(int t) {
	auto & n = Nodes[t];
    if(n.lazy == lazy_zero() and n.flip == 0) return;
	
	int son;
	auto & lz = n.lazy;
	auto flip = n.flip;
	if(son = Nodes[t].son[LEFT]) _dn_(son, lz, flip);
	if(son = Nodes[t].son[RIGHT]) _dn_(son, lz, flip);

	lz = lazy_zero();
	n.flip = 0;
	return;
}

// 分配一个新节点，初始化value和size，其余均为零
int _newNode(const data_type & data) {
	auto & n = Nodes[++toUsed];
	assert(toUsed < Nodes.size());
	n.value = mkValue(n.data = data);
	n.size = 1;
	return toUsed;
}

// 将parent的sn儿子设置为son
void _link(int parent, int sn, int son) {
    Nodes[Nodes[parent].son[sn] = son].parent = parent;
}

// 旋转操作, t不能是树根
void _rotate(int t) {
    assert(t != Root);
	int p = Nodes[t].parent;
	int sn = _sn(t);
	int osn = sn ^ 1;

	// 如果splay紧跟kth调用，则此处无需pushDown
	// 重新确定三对父子关系
	_link(p, sn, Nodes[t].son[osn]);
	if(p != Root) _link(Nodes[p].parent, _sn(p), t);
	else Nodes[t].parent = 0;
	_link(t, osn, p);
	// 只维护p即可
	_pushUp(p);
}

// 将t伸展为p的儿子，如果p为0则将t伸展为树根
void _splay(int p, int t) {
    int pp;
	while((pp = Nodes[t].parent) != p) {
		if(Nodes[pp].parent != p) {
			_sn(pp) == _sn(t) ? _rotate(pp) : _rotate(t);
		}
		_rotate(t);
	}
	_pushUp(t); // 最后维护t
	if(0 == p) Root = t;
	return;
}

// 在t子树上找第k个元素，从0开始
int _kth(int t, int k) {
    assert(0 <= k and k < Nodes[t].size);
	_pushDown(t);
	int son = Nodes[t].son[LEFT];
	int s = son ? Nodes[son].size : 0;
	if(k < s) return _kth(son, k);
	return s < k ? _kth(Nodes[t].son[RIGHT], k - s - 1) : t;
}

void _build(int & t, int parent, int sn, int s, int e, const data_type a[]) {
	int mid = (s + e) >> 1;

	t = _newNode(a[mid]); 
	Nodes[t].parent = parent;

	if(s < mid) _build(Nodes[t].son[LEFT], t, LEFT, s, mid - 1, a);
	if(mid < e) _build(Nodes[t].son[RIGHT], t, RIGHT, mid + 1, e, a);

	_pushUp(t);
	return;
}

// 初始化Nodes, capa典型的取值为(N+insert的节点数量)
void init(int capa){
	/// capa+3, 2个哨兵以及1个零节点
	Nodes.assign(capa + 3, {0, {0, 0}, 0, data_zero(), 0, value_zero(), lazy_zero()});
	toUsed = 0;
	return;
}

// 利用全局数组建树, 数组有效位置为[1...n], 但a[0]与a[n+1]也会被建入
// 如果无需初始化，则调用build(0, {0, 0})即可
void build(int n, const data_type a[]) {
    _build(Root, 0, 0, 0, n + 1, a);    
	return;
}

/// 在pos位置插入一个数据data, pos保证合法
void insert(int pos, const data_type & data) {
    int n = Nodes[Root].size - 2;
	assert(1 <= pos and pos <= n + 1); // n + 1 表示最后一个位置之后

	int t = _kth(Root, pos - 1);
	_splay(0, t); // 将pos-1旋到树根

	int tt = _kth(Root, pos);
	_splay(Root, tt); // 将pos旋到树根的右儿子

	/// 将新节点挂到根的右儿子的左儿子
	t = _newNode(data);
    _link(tt, LEFT, t);
	_pushUp(tt); _pushUp(Root);	
	return;
}

/// 删除区间[s, e]，参数保证合法
void remove(int s, int e) {
	int n = Nodes[Root].size - 2;
	assert(1 <= s and s <= e and e <= n);
    
	int t = _kth(Root, s - 1);
	_splay(0, t);

	int tt = _kth(Root, e + 1);
	_splay(Root, tt);

	Nodes[Nodes[tt].son[LEFT]].parent = 0;
	Nodes[tt].son[LEFT] = 0;
	_pushUp(tt); _pushUp(Root);
	return;
}

/// [s, e]区间内部循环右移k位
void rotate(int s, int e, int k) {
    if(0 == (k %= e - s + 1)) return;
	if(k < 0) k = e - s + 1 + k;
	assert(1 <= k and k <= e - s);

	/// 首先删除[e - k + 1, e]
	int t = _kth(Root, e - k);
	_splay(0, t);
	int tt = _kth(Root, e + 1);
	_splay(Root, tt);
	int son = Nodes[tt].son[LEFT];
	Nodes[tt].son[LEFT] = 0;
	_pushUp(tt); _pushUp(Root);

	/// 再把son插入到s位置
	t = _kth(Root, s - 1);
	_splay(0, t);
	tt = _kth(Root, s);
	_splay(Root, tt);

	_link(tt, LEFT, son);
	_pushUp(tt); _pushUp(Root);
	return;
}

/// 将[s, e]区间移动到pos位置开始, 
/// 原pos位置及以后的数依次后移
/// 调用者需保证pos不在[s, e]区间之中
void move(int s, int e, int pos) {
	int n = Nodes[Root].size - 2;
	assert(1 <= s and s <= e and e <= n);
	assert(1 <= pos and pos <= n + 1); // n + 1表示最后一个位置之后
	assert(pos < s or pos > e);

	int t = _kth(Root, s - 1);
	_splay(0, t);

	int tt = _kth(Root, e + 1);
	_splay(Root, tt);

	int son = Nodes[tt].son[LEFT];
	Nodes[tt].son[LEFT] = 0;
    _pushUp(tt); _pushUp(Root);

	/// 找pos的前一个位置
    t = _kth(Root, pos < s ? pos - 1 : pos - 1 - (e - s + 1));
	_splay(0, t);
    /// 找pos位置
	tt = _kth(Root, pos < s ? pos : pos - (e - s + 1));
	_splay(Root, tt);

	_link(tt, LEFT, son);
	_pushUp(tt); _pushUp(Root);
	return;
}

/// 翻转区间[s, e]
void reverse(int s, int e) {
	int n = Nodes[Root].size - 2;
	assert(1 <= s and s <= e and e <= n);

	int t = _kth(Root, s - 1);
	_splay(0, t);

	int tt = _kth(Root, e + 1);
	_splay(Root, tt);	

	t = Nodes[tt].son[LEFT];

	_dn_(t, lazy_zero(), 1);
	_pushUp(tt); _pushUp(Root);
	return;
}

/// 根据delta的内容修改[s, e]区间的内容，这个操作不改变区间本身的结构
void modify(int s, int e, const lazy_type & delta) {
	int n = Nodes[Root].size - 2;
	assert(1 <= s and s <= e and e <= n);

	int t = _kth(Root, s - 1);
	_splay(0, t);

	int tt = _kth(Root, e + 1);
	_splay(Root, tt);

	/// 根的右儿子的左儿子打标记
	int son = Nodes[tt].son[LEFT];
	assert(son);

	_dn_(son, delta, 0);
	_pushUp(tt); _pushUp(Root);
	return;
}

/// 查询[s, e]区间的信息
value_type query(int s, int e) {
	int n = Nodes[Root].size - 2;
	assert(1 <= s and s <= e and e <= n);
		
    int t = _kth(Root, s - 1);
	_splay(0, t);

	int tt = _kth(Root, e + 1);
	_splay(Root, tt);

	int son = Nodes[tt].son[LEFT];
	return Nodes[son].value;
}

/// 按层次遍历输出SplayTree, 注意要pushDown, 因此不是const
void disp(ostream & os) {
	os << "SplayTree " << Root << ":" << endl;
    queue<int> q;
	q.push(Root);
	while(not q.empty()){
		auto h = q.front(); q.pop();
		_pushDown(h);
		auto & n = Nodes[h];
		os << h << ": (" << n.son[LEFT] << ", " << n.son[RIGHT] << ")";
		os << ", size = " << n.size << ", data = " << n.data;
		os << ", info = " << "{" << n.value.cnt[0] << ", " << n.value.cnt[1] << "}";
        os << "{" << n.value.longest[0] << ", " << n.value.longest[1] << "}";
        os << "{{" << n.value.bound[0].first << ", " << n.value.bound[0].second << "}, {";
        os << n.value.bound[1].first << ", " << n.value.bound[1].second << "}}";
        os << "," << n.value.duanshu;
		os << endl;
		if(n.son[LEFT]) q.push(n.son[LEFT]);
		if(n.son[RIGHT]) q.push(n.son[RIGHT]);
	}
	return;
}

/// 中序遍历输出原始数组, 要pushDown
void dispInOrder(ostream & os) {
    function<void(int)> __dfs = [&, this](int u){
        this->_pushDown(u);
		auto & n = this->Nodes[u];
		int son = n.son[LEFT];
		if(son) __dfs(son);
		os << n.data << " ";
		if(son = n.son[RIGHT]) __dfs(son);
	};

	auto t = _kth(Root, 0);
	_splay(0, t);
	auto tt = _kth(Root, Nodes[Root].size - 1);
	_splay(Root, tt);
	t = Nodes[tt].son[LEFT];
	__dfs(t);
    os << std::endl;
	return;
}

}St;



int main(){
#ifndef ONLINE_JUDGE
    //freopen("z.txt", "r", stdin);
#endif
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(0);
    int n, m; cin >> n >> m;
    
    St.init(n + n);
    vector<int> vec(n + 2, 0);
    for(int i=1;i<=n;i+=2) vec[i] = 1;
    St.build(n, vec.data());
    // St.disp(cout);

    SplayTree::value_type ans;
    for(int op,s,e,v,i=1;i<=m;++i){
        // cout << i << ":\n";
        // St.disp(cout);
        cin >> op >> s >> e;
        switch(op){
            case 1: cin >> v; St.modify(s, e, v ? 2 : 4); break;
            case 2: St.modify(s, e, 1); break;
            case 3: ans = St.query(s, e); cout << ans.cnt[1] << "\n"; break;
            case 4: ans = St.query(s, e); cout << ans.longest[1] << "\n"; break;
            case 5: ans = St.query(s, e); cout << ans.cnt[0] << "\n"; break;
            case 6: ans = St.query(s, e); cout << ans.longest[0] << "\n"; break;
            case 7: ans = St.query(s, e); cout << ans.duanshu << "\n"; break;
            case 8: St.reverse(s, e); break;
            case 9: cin >> v; St.rotate(s, e, v); break;
            case 10: {
                cin >> v;
                if(v == s) break;
                if(v > s) v += e - s + 1;
                St.move(s, e, v);
                break;
            }
            case 11: St.remove(s, e); break;
            case 12: St.insert(s, e); break;
            default:assert(0);
        }
         


    }
    return 0;
}